// Package cert 证书管理
package cert

import (
	crand "crypto/rand"
	"crypto/rsa"
	"crypto/tls"
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/pem"
	"fmt"
	"math/big"
	"math/rand"
	"net"
	"time"
)

var (
	rootCA  *x509.Certificate
	rootKey *rsa.PrivateKey
)

func init() {
	rand.Seed(time.Now().UnixNano())
	var err error
	rootCA, err = loadRootCA()
	if err != nil {
		fmt.Errorf("加载根证书失败: %s", err)
	}
	rootKey, err = loadRootKey()
	if err != nil {
		fmt.Errorf("加载根证书私钥失败: %s", err)
	}
}

// Certificate 证书管理
type Certificate struct {
}

// Generate 生成证书
func (c *Certificate) Generate(host string) (*tls.Config, error) {

	if h, _, err := net.SplitHostPort(host); err == nil {
		host = h
	}

	// 先从缓存中查找证书
	value, ok := Cache[host]
	if ok {
		tlsConf := &tls.Config{InsecureSkipVerify: true,
			Certificates: []tls.Certificate{*value},
		}
		return tlsConf, nil
	}

	priv, err := rsa.GenerateKey(crand.Reader, 2048)
	if err != nil {
		return nil, err
	}

	tmpl := c.template(host)
	derBytes, err := x509.CreateCertificate(crand.Reader, tmpl, rootCA, &priv.PublicKey, rootKey)
	if err != nil {
		return nil, err
	}
	certBlock := &pem.Block{
		Type:  "CERTIFICATE",
		Bytes: derBytes,
	}
	serverCert := pem.EncodeToMemory(certBlock)

	keyBlock := &pem.Block{
		Type:  "RSA PRIVATE KEY",
		Bytes: x509.MarshalPKCS1PrivateKey(priv),
	}
	serverKey := pem.EncodeToMemory(keyBlock)

	cert, err := tls.X509KeyPair(serverCert, serverKey)
	if err != nil {
		return nil, err
	}
	tlsConf := &tls.Config{InsecureSkipVerify: true,
		Certificates: []tls.Certificate{cert},
	}

	// 缓存证书
	Cache[host] = &cert

	return tlsConf, nil
}

func (c *Certificate) template(host string) *x509.Certificate {
	cert := &x509.Certificate{
		SerialNumber: big.NewInt(rand.Int63()),
		Subject: pkix.Name{
			CommonName: host,
		},
		NotBefore:             time.Now().AddDate(-1, 0, 0),
		NotAfter:              time.Now().AddDate(1, 0, 0),
		BasicConstraintsValid: true,
		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
		KeyUsage:              x509.KeyUsageDigitalSignature | x509.KeyUsageDataEncipherment,
		EmailAddresses:        []string{"962584902@qq.com"},
	}

	if ip := net.ParseIP(host); ip != nil {
		cert.IPAddresses = []net.IP{ip}
	} else {
		cert.DNSNames = []string{host}
	}

	return cert
}

// 加载根证书
func loadRootCA() (*x509.Certificate, error) {
	block, _ := pem.Decode([]byte(`-----BEGIN CERTIFICATE-----
MIIEdjCCA16gAwIBAgIJAKjAlWVJgmtoMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYD
VQQGEwJDTjERMA8GA1UECBMIc2hhbmdoYWkxETAPBgNVBAcTCHNoYW5naGFpMQ0w
CwYDVQQKEwR0ZXN0MQ8wDQYDVQQLEwZ0ZXN0ZXIxDDAKBgNVBAMTA0pZRDEfMB0G
CSqGSIb3DQEJARYQOTYyNTg0OTAyQHFxLmNvbTAgFw0xOTEwMjAxMjIxMjdaGA8y
MTE5MDkyNjEyMjEyN1owgYIxCzAJBgNVBAYTAkNOMREwDwYDVQQIEwhzaGFuZ2hh
aTERMA8GA1UEBxMIc2hhbmdoYWkxDTALBgNVBAoTBHRlc3QxDzANBgNVBAsTBnRl
c3RlcjEMMAoGA1UEAxMDSllEMR8wHQYJKoZIhvcNAQkBFhA5NjI1ODQ5MDJAcXEu
Y29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxSJ490RGtj2iYQDN
Br3Gt2JleCUDSpirKcqsxfh3i8UHgLfp1yQ+zmSouqlSuIFmGJvQiHH4Qky4GSOc
+Sa2gEybBWSyDMVTKOkhhl6OzCBXxakS6kstYrL/o9Q3PR6Gjlg7KPacO//uzzDB
oeHHmrNzOLP1jJ/jJzjOdv5lBO6wnlQUBek/pR/EIz5Q55+bFnYMhE/B/KV5moht
IWgDk1OqQjq49cIoj3dgtALXe6cc3nno4Bo62MXrAFagBouwmojD/ipe10H35Oyq
ZllOL5WNt5q9aNd16KE2YzM408BlUZXHq3pzvgURNyw4ux7BDcnk0Oy5OI8FBsRV
9tJsSwIDAQABo4HqMIHnMB0GA1UdDgQWBBST5sNhq/aUKrjjCMhJpVxGlOnpGDCB
twYDVR0jBIGvMIGsgBST5sNhq/aUKrjjCMhJpVxGlOnpGKGBiKSBhTCBgjELMAkG
A1UEBhMCQ04xETAPBgNVBAgTCHNoYW5naGFpMREwDwYDVQQHEwhzaGFuZ2hhaTEN
MAsGA1UEChMEdGVzdDEPMA0GA1UECxMGdGVzdGVyMQwwCgYDVQQDEwNKWUQxHzAd
BgkqhkiG9w0BCQEWEDk2MjU4NDkwMkBxcS5jb22CCQCowJVlSYJraDAMBgNVHRME
BTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAII3S4lfexudO9yc0ZWckKMoNadHIG
ofnQQACZzk8bSxEZN75MRmq4wQbzIz7lyOLORNmNGPVTF9nngJsfUfzIBFJuf2+B
CE4ra60f0MmwwRZMIy9tGk0x5RKfGHCcdJio17qrnrNAlZXD0PJv3bpjconGZk3y
dl9GfeAl3Gd+bffkbAcz7thOLGuY3gjGv7cbJFuBs0DM1SXS5d1Vhtqb7tLVpaAf
XGAlkDG/yLW1rouauy5t09ar3HFhClL46G7XFTLrmsiJtj0dID7GwNt0DDoGmO+/
pCqXhKPc8ommCkIN6QObmnU4LM7kk6rMWhjsfmEOsr5V6UjBuOaV19QP
-----END CERTIFICATE-----`))

	return x509.ParseCertificate(block.Bytes)
}

// 加载根证书私钥
func loadRootKey() (*rsa.PrivateKey, error) {
	block, _ := pem.Decode([]byte(`-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAxSJ490RGtj2iYQDNBr3Gt2JleCUDSpirKcqsxfh3i8UHgLfp
1yQ+zmSouqlSuIFmGJvQiHH4Qky4GSOc+Sa2gEybBWSyDMVTKOkhhl6OzCBXxakS
6kstYrL/o9Q3PR6Gjlg7KPacO//uzzDBoeHHmrNzOLP1jJ/jJzjOdv5lBO6wnlQU
Bek/pR/EIz5Q55+bFnYMhE/B/KV5mohtIWgDk1OqQjq49cIoj3dgtALXe6cc3nno
4Bo62MXrAFagBouwmojD/ipe10H35OyqZllOL5WNt5q9aNd16KE2YzM408BlUZXH
q3pzvgURNyw4ux7BDcnk0Oy5OI8FBsRV9tJsSwIDAQABAoIBAFSixT6b4KQTeCif
eGcBiVRoeVoIwg3/19S8gEsKrwCiGeOIkmvc0t431z00vyAZ5iSAmRpLnCOS3qNk
Z9uMZGRW/2NkZREYkuiIlu0iobo/1I83VLikiBrM8PZ8gS7LcUeh19xxbIhSDEyG
CUwgLFtd2gUpNi4m4xaOzA3IkMR5mDdvOERM3l8gmHiZEDXsWBpSirguPAvBq6DP
rkWk/zYkSVtBC+z1pM2BMsQnqDPlgDAPF0G1Tt7JF2RBsdS3Lwb3ucQx9mz8MVLb
z6spNsSAnt6x4xqBxDS4g4+xyxAzp0DArYQ9ZRYd18AMRQIn49Vgk2nRO+5bZXy4
AkEZaeECgYEA9tPZj9Ou7vk+KsUpMz+ztOnPP/JgRQMvsVeLYyunW3T0rfaPCxVM
padMoOroe52jyJuCo5Uowbo1N14cokqhXwsCA+/LRukWKv8ctTbU41VOb0vPth3F
MW6efYk6o19wP2cP13efpuN86NZhQFqm/GekDvhz3oMeMc6JxxJI2zsCgYEAzHXg
1HdUFajcY69/qL4NfW2imGTDPasUmXJCtpbDcS59H7E7UnmNNvYyVa/E8xFI6+0C
55KUFR5iNSLk/AwP/PHYZF0hEH9bVh5P0i8+0NRVQ2vQQLWT5Oc4dqG/yPpxgfEv
DkhMqbhlQfkEWlpdINliy8556Xqk7sSz3djeAjECgYBZOc39Ay3Kr4j8lxdEsnN5
I8hKuoh4iiVUe2wk5mPyWL4WoPmmrQVvIKI/zYtLHHpXi3fXQJViKrkQEdJSDJ53
KBiLacTXFm1wD5bGH1Mn9u+KpiIpGGvvaaibgt8Sre56zPvaDSFGiBfgZ5byV5Lj
zWduDfx85HMm2B3QO9jgfwKBgApniTxmoiHECQsNmDp3CWqzlI2auxC9TvwMA3cV
LvbofbeKJlGpG9WLK76OhkA0Rfizg+1S2TRF6ot3rh1hY8Lkb7WTw6X6RSSZwEga
3WB1Ha2jo+JXGyKP3aCz1HWewP3yzwk0BqqwVn7H9D/Az3JnfY6PgEawVgpMeja0
3X9RAoGAJefeg/mPuLrsnKAJvIn9QPZag3N38e53wT0QuAnaQmx9pfAep9i8njjS
ksuUcy9340mBLiYKCex3/UKUqnNLiY9uAKDuXnAlvLPhCHYYHDuOq/HUHL0mSitU
YijUy3ApiW+gCUTbVYtqptYkGfZMFIL5GKg7syTl1aeJb8EPqK4=
-----END RSA PRIVATE KEY-----`))

	return x509.ParsePKCS1PrivateKey(block.Bytes)
}
